package com.libleveldb.implementation

import android.util.Log
import com.libleveldb.WriteBatch
import java.io.Closeable

/**
 * Native object a-la <tt>leveldb::WriteBatch</tt>.
 *
 * Make sure after use you call [NativeWriteBatch.close].
 */
open class NativeWriteBatch(writeBatch: WriteBatch) : Closeable {
    companion object {
        /**
         * Native create. Corresponds to: <tt>new leveldb::SimpleWriteBatch()</tt>
         *
         * @return pointer to nat structure
         */
        private external fun nativeCreate(): Long

        /**
         * Native SimpleWriteBatch put. Pointer is unchecked.
         *
         * @param nwb   nat structure pointer
         * @param key
         * @param value
         */
        private external fun nativePut(nwb: Long, key: ByteArray?, value: ByteArray?)

        /**
         * Native SimpleWriteBatch delete. Pointer is unchecked.
         *
         * @param nwb nat structure pointer
         * @param key
         */
        private external fun nativeDelete(nwb: Long, key: ByteArray?)

        /**
         * Native close. Releases all memory. Pointer is unchecked.
         *
         * @param nwb nat structure pointer
         */
        private external fun nativeClose(nwb: Long)

        init {
            System.loadLibrary("leveldb-android")
        }
    }

    // Don't touch this. If you do, something somewhere dies.
    private var nwb: Long

    /**
     * Returns the nat object's pointer, to be used when calling a nat function.
     *
     * @return the nat pointer
     */
    fun nativePointer(): Long {
        return nwb
    }

    /**
     * Close this object. You may call this multiple times.
     *
     * Use of this object is illegal after calling this.
     */
    override fun close() {
        if (!isClosed) {
            nativeClose(nwb)
            nwb = 0
        } else {
            Log.i("org.leveldb", "Native WriteBatch is already closed.")
        }
    }

    /**
     * Whether this object is closed.
     *
     * @return
     */
    val isClosed: Boolean
        get() = nwb == 0L

    init {
        nwb = nativeCreate()
        for (operation in writeBatch) {
            if (operation != null) {
                if (operation.isPut) {
                    nativePut(nwb, operation.key(), operation.value())
                } else {
                    nativeDelete(nwb, operation.key())
                }
            }
        }
    }
}